package com.bbx.iotdb.iotdbdemo.native_api;

import lombok.extern.slf4j.Slf4j;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.Session;
import org.apache.iotdb.session.SessionDataSet;
import org.apache.iotdb.session.pool.SessionDataSetWrapper;
import org.apache.iotdb.session.pool.SessionPool;
import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.apache.iotdb.tsfile.read.common.Field;
import org.apache.iotdb.tsfile.read.common.RowRecord;
import org.apache.iotdb.tsfile.write.record.Tablet;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;


/**
 * Native api
 */
@Slf4j
@RequestMapping("/native")
@RestController
public class NativeApiTest {

    /**
     * 获取连接 单个连接
     *
     * @return
     * @throws IoTDBConnectionException
     */
    private Session getSession() throws IoTDBConnectionException {
        Session session = new Session("192.168.10.85", 6667, "root", "root");
        session.open();
        return session;
    }


    /**
     * 获取连接池
     * 注意事项
     * 1、如果60 秒内获取不到连接，会记录警告日志，程序将会被挂起，
     * 2、连接使用完毕后将回重新放入连接池，如果连接损毁，会将这个连接从连接池中移除，重新创建一个新的连接
     * 对于查询操作，需要特别注意
     * 通过 sessionPool 查询数据，将会返回一个  SessionDataSetWrapper ，
     *      * 如果没有对SessionDataSetWrapper  内的数据全部遍历，将会出现一个异常，通常不得不去调用SessionPool.closeResultSet(wrapper)
     *      * 如果 SessionDataSetWrapper  调用了 hasNext() 或者 next() ，通常也需要调用   SessionPool.closeResultSet(wrapper)
     *
     * @return
     */
    private SessionPool getSessionFromPool() {
        SessionPool sessionPool = new SessionPool("192.168.10.85", 6667, "root", "root", 5);
        return sessionPool;
    }

    /**
     * 创建 storage group
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @ResponseBody
    @RequestMapping("/setStroageGroup")
    public void setStroageGroup() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
        session.setStorageGroup("root.dev");
        session.close();
    }

    /**
     * 查询 Storage Group
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @RequestMapping("/selectStroageGroup")
    public void selectStroageGroup() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
        String sql = "show storage group";
        SessionDataSet sessionDataSet = session.executeQueryStatement(sql);
        while (sessionDataSet.hasNext()) {
            RowRecord rowRecord = sessionDataSet.next();
            rowRecord.getFields().forEach(i -> log.info("[{}]", i.toString()));
        }
        session.close();
    }


    /**
     * 删除 Storage Group
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @RequestMapping("/deleteStorageGroup")
    public void deleteStorageGroup() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
        session.deleteStorageGroup("root.dev");
        session.close();
    }


    /**
     * 创建 timeseries
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @RequestMapping("createTimeseries")
    @ResponseBody
    public void createTimeseries() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
        session.createTimeseries("root.dev.wf04.wt04.status", TSDataType.BOOLEAN, TSEncoding.PLAIN, CompressionType.SNAPPY);
        session.close();
    }

    /**
     * 查询时间序列
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @RequestMapping("/selectTimeSeries")
    public void selectTimeSeries() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
        String sql = "show timeseries";
        SessionDataSet sessionDataSet = session.executeQueryStatement(sql);
        while (sessionDataSet.hasNext()) {
            RowRecord rowRecord = sessionDataSet.next();
            Field field = rowRecord.getFields().get(0);
            log.info("timeseries field [{}]", field.toString());
        }
        session.close();
    }

    /**
     * 删除 timeseries
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @RequestMapping("/deleteTimeseries")
    public void deleteTimeseries() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
//        session.deleteTimeseries("root.jdbc.wf05.wt05.status");
        session.deleteTimeseries("root.jdbc.wf05.wt05.stauts");
        session.close();
    }


    /**
     * 插入数据
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @ResponseBody
    @RequestMapping("/insertRecord")
    public void insertRecord() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
        List<String> measurements = new ArrayList<>();
        measurements.add("status");
        List<TSDataType> types = new ArrayList<>();
        types.add(TSDataType.BOOLEAN);
        session.insertRecord("root.test.wf02.wt02", System.currentTimeMillis(), measurements, types, false);
        session.close();
    }

    /**
     * 查询数据
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @RequestMapping("/selectData")
    public void selectData() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
        ArrayList<String> paths = new ArrayList<>();
        paths.add("root.ln.wf01.wt01");
        SessionDataSet sessionDataSet = session.executeRawDataQuery(paths, 10L, 110L);

        while (sessionDataSet.hasNext()) {
            RowRecord rowRecord = sessionDataSet.next();
            log.info("[{}][{}]", rowRecord.getTimestamp(), rowRecord.toString());
            //方法一：toString() 是将field 通过‘\t’ 分割的，因此此处可以使用
            String[] split = rowRecord.toString().split("\t");
            log.info("s0[{}],s1[{}],s2[{}]", split[0], split[1], split[2]);
            //方法二：通过迭代器处理
            Iterator<Field> iterator = rowRecord.getFields().iterator();
            while (iterator.hasNext()) {
                Field field = iterator.next();
                log.info("field[{}]", field);
            }
        }
        session.close();
    }


    /**
     * 创建表 ，相当与多次创建 timerservies
     * <p>
     * 下面示例等同于执行一下sql
     * create timeseries root.dev.wf04.wt04.status with DATATYPE= boolean ,encoding=RLE
     * create timeseries root.dev.wf04.wt04.insertTable with DATATYPE= float ,encoding=GORILLA
     * create timeseries root.dev.wf04.wt04.time with DATATYPE= INT64 ,encoding=RLE
     * insert Table
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @RequestMapping("/insertTable")
    public void insertTable() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
        List<MeasurementSchema> schemas = new ArrayList<>();
        MeasurementSchema measurementSchema1 = new MeasurementSchema("status", TSDataType.BOOLEAN);
        MeasurementSchema measurementSchema2 = new MeasurementSchema("insertTable", TSDataType.FLOAT);
        MeasurementSchema measurementSchema3 = MeasurementSchema.TIME_SCHEMA;
        schemas.add(measurementSchema1);
        schemas.add(measurementSchema2);
        schemas.add(measurementSchema3);
        Tablet tablet = new Tablet("root.dev.wf04.wt04", schemas);
        session.insertTablet(tablet);
        session.close();
    }

    /**
     * 用于测试从Client 插入数据消耗的的时间，并不会真正的插入数据，server 端接收数据后只做了返回
     *
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    @RequestMapping("/testInsertRecord")
    public void testInsertRecord() throws IoTDBConnectionException, StatementExecutionException {
        Session session = getSession();
        List<String> measurements = new ArrayList<>();
        List<String> values = new ArrayList<>();
        measurements.add("status");
        measurements.add("insertTable");
        measurements.add("time");
        values.add("true");
        values.add("1.11");
        values.add("5000");
        session.testInsertRecord("root.dev.wf04.wt04", System.currentTimeMillis(), measurements, values);
    }

    /**
     *
     * 通过 sessionPool 查询数据，将会返回一个  SessionDataSetWrapper ，
     * 如果没有对SessionDataSetWrapper  内的数据全部遍历，将会出现一个异常，通常不得不去调用SessionPool.closeResultSet(wrapper)
     * 如果 SessionDataSetWrapper  调用了 hasNext() 或者 next() ，通常也需要调用   SessionPool.closeResultSet(wrapper)
     *
     * @throws StatementExecutionException
     * @throws IoTDBConnectionException
     */
    @RequestMapping("/selectDataBySessionPool")
    public void selectDataBySessionPool() throws StatementExecutionException, IoTDBConnectionException {
        SessionPool sessionFromPool = getSessionFromPool();

        String sql = "select * from root.ln.wf01.wt01";
        SessionDataSetWrapper sessionDataSetWrapper = sessionFromPool.executeQueryStatement(sql);
        List<String> columnNames = sessionDataSetWrapper.getColumnNames();

        while (sessionDataSetWrapper.hasNext()) {
            RowRecord rowRecord = sessionDataSetWrapper.next();
            log.info("[{}]", rowRecord.toString());
            List<Field> fields = rowRecord.getFields();
            log.info("timeseries[{}],columnName[{}],field[{}]",rowRecord.getTimestamp(), columnNames.get(0), fields.get(0));
        }

        int canUserSize = sessionFromPool.currentAvailableSize();
        int notCanUserSize = sessionFromPool.currentOccupiedSize();
        log.info("canUserSize[{}],notCanUserSize[{}]", canUserSize,notCanUserSize);

        sessionFromPool.closeResultSet(sessionDataSetWrapper);





    }


}
